using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;

namespace ViewOnCore.Helper.WPF
{
    public delegate void GradientChangedHandler(LinearGradientBrush brush);

    public partial class GradientPicker : System.Windows.Controls.UserControl
    {

        #region Variables

        private LinearGradientBrush _brush;

        private List<Slider> _sliders = new List<Slider>();

        private Slider _currentSlider;

        public event GradientChangedHandler GradientChanged;

        #endregion

        #region Constructor

        public GradientPicker()
        {
            InitializeComponent();

            popup.MouseLeave += new MouseEventHandler(popup_MouseLeave);
            popup.KeyDown += new KeyEventHandler(popup_KeyDown);

            colorPicker.SelectedColorChanged += new RoutedPropertyChangedEventHandler<Color>(colorPicker_SelectedColorChanged);

            recGradient.MouseLeftButtonUp += new MouseButtonEventHandler(recGradient_MouseLeftButtonUp);

            AddSlider(0, Color.FromArgb(0, 0, 0, 0));
            AddSlider(100, Color.FromArgb(255, 255, 255, 255));
            GenerateBrush();
        }

        #endregion

        #region SetBrush

        public void SetBrush(LinearGradientBrush brush)
        {
            //---- Clean
            foreach(Slider slider in _sliders)
                griSliders.Children.Remove(slider);
            _sliders.Clear();

            //----
            foreach (GradientStop stop in brush.GradientStops)
                AddSlider(stop.Offset * 100, stop.Color);

            GenerateBrush();
        }

        #endregion

        #region AddSlider

        private void AddSlider(double value, Color color)
        {
            Slider slider = new Slider();
            slider.Style = (Style)FindResource("GradientPicker.Slider");
            slider.Maximum = 100;

            slider.Tag = color;

            slider.Value = value;

            slider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(slider_ValueChanged);

            slider.AddHandler(Slider.PreviewMouseDownEvent, new MouseButtonEventHandler(slider_MouseLeftButtonDown), true);
            slider.AddHandler(Slider.MouseDoubleClickEvent, new MouseButtonEventHandler(slider_MouseDoubleClick), true);
            slider.KeyUp += new KeyEventHandler(slider_KeyUp);

            _sliders.Add(slider);
            griSliders.Children.Add(slider);
        }

        #endregion

        #region DeleteCurrentSlider

        private void DeleteCurrentSlider()
        {
            if (_sliders.Count < 3)
                return;

            _sliders.Remove(_currentSlider);
            griSliders.Children.Remove(_currentSlider);

            _currentSlider = _sliders[_sliders.Count - 1];

            if (popup.IsOpen)
                popup.IsOpen = false;

            GenerateBrush();
        }

        #endregion

        #region GenerateBrush

        private void GenerateBrush()
        {
            _brush = new LinearGradientBrush();

            _brush.StartPoint = new Point(0, 0);
            _brush.EndPoint = new Point(1, 0);

            foreach (Slider slider in _sliders)
            {
                GradientStop stop = new GradientStop();
                stop.Offset = slider.Value / 100;
                stop.Color = (Color)slider.Tag;

                _brush.GradientStops.Add(stop);
            }

            recGradient.Fill = _brush;

            if (GradientChanged != null)
            {
                // Vertical one
                LinearGradientBrush clone = _brush.Clone();
                clone.StartPoint = new Point(0, 0);
                clone.EndPoint = new Point(0, 1);

                GradientChanged(clone);
            }
        }

        #endregion

        #region Events

        void slider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _currentSlider = sender as Slider;
            colorPicker.SelectedColor = (Color)_currentSlider.Tag;
            popup.IsOpen = true;
        }

        void slider_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            DeleteCurrentSlider();
        }

        void slider_KeyUp(object sender, KeyEventArgs e)
        {
            DeleteCurrentSlider();
        }

        void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            GenerateBrush();
        }

        void colorPicker_SelectedColorChanged(object sender, RoutedPropertyChangedEventArgs<Color> e)
        {
            _currentSlider.Tag = e.NewValue;
            GenerateBrush();
        }

        void popup_MouseLeave(object sender, MouseEventArgs e)
        {
            popup.IsOpen = false;
        }

        void popup_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                popup.IsOpen = false;
        }

        void recGradient_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //----
            double position = e.GetPosition(recGradient).X / 2;
            Color color = GetPixelColor();

            //----
            AddSlider(position, color);
        }

        #endregion

        #region ONHOLD : ROTATION

        //void txtRotation_TextChanged(object sender, TextChangedEventArgs e)
        //{
        //    //_brush.Transform.
        //    //new LinearGradientBrush(

        //    /*
        //    <LinearGradientBrush.Transform>
        //        <TransformGroup>
        //            <ScaleTransform ScaleX="1" ScaleY="1"/>
        //            <SkewTransform AngleX="0" AngleY="0"/>
        //            <RotateTransform Angle="90"/>
        //            <TranslateTransform X="0" Y="0"/>
        //        </TransformGroup>
        //    </LinearGradientBrush.Transform>*/

        //}

        #endregion

        #region Helpers

        private struct POINT
        {
            public uint X;
            public uint Y;
        }

        [DllImport("gdi32")]
        private static extern int GetPixel(int hdc, int xPos, int yPos);

        [DllImport("user32")]
        private static extern int GetWindowDC(int hwnd);

        [DllImport("user32")]
        private static extern int GetCursorPos(out POINT point);

        private static Color GetPixelColor()
        {
            POINT point;
            GetCursorPos(out point);

            Point pos = new Point(point.X, point.Y);

            int dc = GetWindowDC(0);
            int intColor = GetPixel(dc, (int)pos.X, (int)pos.Y);

            //byte a = (byte)( ( intColor >> 0x18 ) & 0xffL );
            byte b = (byte)((intColor >> 0x10) & 0xffL);
            byte g = (byte)((intColor >> 8) & 0xffL);
            byte r = (byte)(intColor & 0xffL);

            return Color.FromRgb(r, g, b);
        }

        #endregion

    }
}